package org.mozhu.mboot.admin.maintain.configuration.web.controller;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.mozhu.mboot.core.config.ApplicationConfiguration;
import org.mozhu.mboot.core.data.Searchable;
import org.mozhu.mboot.core.support.datatable.DTReturnObject;
import org.mozhu.mboot.core.support.datatable.DTUtils;
import org.mozhu.mboot.core.web.AjaxResponse;
import org.mozhu.mboot.core.web.controller.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.Comparator;
import java.util.List;
import java.util.TreeMap;

@RequestMapping("/maintain/configuration")
@Controller
public class ConfigurationController extends BaseController {

    @Autowired
    ApplicationConfiguration applicationConfiguration;

    @RequestMapping
    public String list(HttpServletRequest request, Model model) {
        return viewName("list");
    }

    @RequestMapping(headers = "ajax=true", method = RequestMethod.POST)
    @ResponseBody
    public Object list(HttpServletRequest request, Searchable searchable) {
        Comparator comparator = Comparator.naturalOrder();
        if (searchable.hashSort()) {
            Sort.Order order = searchable.getSort().getOrderFor("key");
            if (order != null && Sort.Direction.DESC.equals(order.getDirection())) {
                comparator = Comparator.naturalOrder().reversed();
            }
        }

        String searchLikeKeyOrValue = request.getParameter("search_LIKE_key_OR_value");

        TreeMap<String, String> properties = new TreeMap<>(comparator);
        applicationConfiguration.getProperties().forEach((k, v) -> {
            if (isMatch(k, v, searchLikeKeyOrValue)) {
                properties.put(k, v);
            }
        });

        List<String> keyList = Lists.newArrayList(properties.navigableKeySet());
        Pageable pageable = searchable.getPage();
        int total = properties.size();
        long endIndex = pageable.getOffset() + pageable.getPageSize();
        endIndex = endIndex > total ? total : endIndex;
        List<String> subKeyList = keyList.subList((int) pageable.getOffset(), (int) endIndex);
        List<Configuration> configurations = Lists.newArrayList();
        for (Object key : subKeyList) {
            configurations.add(new Configuration(key.toString(), properties.get(key)));
        }
        Page<Configuration> page = new PageImpl<Configuration>(configurations, pageable, total);

        DTReturnObject<Configuration> dtReturnObject = DTUtils.toDTReturnObject(page);
        dtReturnObject.setDraw(request.getParameter("draw"));
        return dtReturnObject;
    }

    @RequestMapping(value = {"/update"})
    @ResponseBody
    public Object update(HttpServletRequest request, @RequestParam(name = "key") String key, @RequestParam(name = "value") String value) {
        applicationConfiguration.setProperty(key, value);
        return AjaxResponse.success();
    }

    private boolean isMatch(String k, String v, String searchLikeKeyOrValue) {
        if (StringUtils.isNotBlank(searchLikeKeyOrValue)) {
            return k.contains(searchLikeKeyOrValue) || v.contains(searchLikeKeyOrValue);
        }
        return true;
    }

    public static class Configuration {
        private String key;
        private String value;

        public Configuration(String key, String value) {
            this.key = key;
            this.value = value;
        }

        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }

}